//
// Created by kevin on 2024/11/26.
//



#include<string>
#include<iostream>
#include "lte_type.h"
#include "lte_para.h"
#include "lte_getDefaultTM.h"

void lte_getDefaultTM(const std::string testModelNo, const std::string bandwidth,
                      int cellID, const std::string duplexingMode, sTM& defaultTM,
                      sCHS & defaultCHS) {
    defaultTM.TMN = testModelNo;

    defaultTM.BW = bandwidth;

    defaultTM.NDLRB = getNDLRB(bandwidth);
    defaultTM.CellRefP = 1;
    defaultTM.NCellID = getNcellId(testModelNo, bandwidth);

    defaultTM.NCellID = cellID;

    defaultTM.CyclicPrefix = "Normal";
    defaultTM.CFI = 1;
    defaultTM.Ng = "Sixth";
    defaultTM.PHICHDuration = "Normal";
    defaultTM.NSubframe = 0;
    defaultTM.TotSubframes = 10;
    defaultTM.Windowing = 0;
    defaultTM.Nfft = NULL;
    defaultTM.DuplexMode = duplexingMode;

    defaultTM.PDSCHPowerBoosted = getPDSCHBoosted(testModelNo, bandwidth);
    defaultTM.PDSCHPowerDeboosted = getPDSCHDeboosted(testModelNo, bandwidth);

    int res = defaultTM.DuplexMode.compare("TDD");
    if (res == 0) {
        defaultTM.TDDConfig = 3;
        defaultTM.SSC = 8;
    }
    defaultCHS.TxScheme = "Port0";
    defaultCHS.Modulation = getPDSCHModulation(testModelNo);
    defaultCHS.NLayers = 1;
}


unsigned int getNDLRB(const std::string bw) {
    int ndlrb = 0;
    std::string mod = bw;

    toupper(mod);

    auto it = BandInfo.find(mod);
    if(it == BandInfo.end()){
        std::cout << "lte:error, The function call resulted in an error: The input parameter BW should be one of {''1.4MHz'', ''3MHz'', ''5MHz'', ''10MHz'', ''15MHz'', "
                     "''20MHz'', ''9RB'', ''11RB'', ''27RB'', ''45RB'', ''64RB'', ''91RB''}\"" <<std::endl;
    }

    switch(it->second){
        case D1Dot4MHZ:{
            ndlrb = 6;
            break;
        }
        case D3MHz:{
            ndlrb = 6;
            break;
        }
        case D5MHz:{
            ndlrb = 25;
            break;
        }
        case D10MHz:{
            ndlrb = 50;
            break;
        }
        case D15MHz:{
            ndlrb = 75;
            break;
        }
        case D20MHz:{
            ndlrb = 100;
            break;
        }
        case D9RB:{
            ndlrb = 9;
            break;
        }
        case D11RB:{
            ndlrb = 11;
            break;
        }
        case D27RB:{
            ndlrb = 27;
            break;
        }
        case D45RB:{
            ndlrb = 45;
            break;
        }
        case D64RB:{
            ndlrb = 64;
            break;
        }
        case D91RB:{
            ndlrb = 91;
            break;
        }
    }

    return ndlrb;
}

unsigned int getNcellId(const std::string testModelNo, const std::string bandwidth) {
    unsigned int nCellId = 1;
    std::string validBwCustom[] = {"9RB","11RB","27RB","45RB","64RB","91RB"};
    int res = testModelNo.compare("1.1");

    int rr = -1;
    int len = sizeof(validBwCustom) / sizeof(validBwCustom[0]); // 计算数组中元素的数量
    for (int i = 0; i < len; i++) {
        rr = bandwidth.compare(validBwCustom[i]);
        if (rr == 0) {
            break;
        }
    }

    if (res == 0 && rr == 0) {
        nCellId = 10;
    }

    return nCellId;
}

double getPDSCHBoosted(const std::string tmNo, const std::string bw) {
    double power = 0;

    int res = tmNo.compare("1.2");
    if (res == 0) {
        power = 3;
        return power;
    }
    std::string mod = bw;
    toupper(mod);
    res = tmNo.compare("3.2");
    if (res == 0) {
        auto it = BandWidth.find(mod);
        if(it == BandWidth.end()){
            std::cout << "lte:error, The function call resulted in an error : The input parameter BW should be one of{''1.4MHz'', ''3MHz'', ''5MHz'', ''10MHz'', ''15MHz'', ''20MHz''})" <<std::endl;
        }

        switch(it->second){
            case D1Dot4MHZ:{
                power = 3.005;
                break;
            }
            case D3MHz:{
                power = 1.573;
                break;
            }
            case D5MHz:{
                power = 2.426;
                break;
            }
            case D10MHz:{
                power = 2.426;
                break;
            }
            case D15MHz:{
                power = 3.005;
                break;
            }
            case D20MHz:{
                power = 2.426;
                break;
            }
        }

        return power;
    }
    res = tmNo.compare("3.3");
    if (res == 0) {
        auto it = BandWidth.find(mod);
        if(it == BandWidth.end()){
            std::cout << "lte:error, The function call resulted in an error : The input parameter BW should be one of{''1.4MHz'', ''3MHz'', ''5MHz'', ''10MHz'', ''15MHz'', ''20MHz''})" << std::endl;
        }
        switch(it->second){
            case D1Dot4MHZ:{
                power = 2.427;
                break;
            }
            case D3MHz:{
                power = 2.189;
                break;
            }
            case D5MHz:{
                power = 2.580;
                break;
            }
            case D10MHz:{
                power = 2.427;
                break;
            }
            case D15MHz:{
                power = 2.477;
                break;
            }
            case D20MHz:{
                power = 2.427;
                break;
            }
        }

        return power;
    }

    return power;
}

double getPDSCHDeboosted(const std::string tmNo, const std::string bw) {
    double power = 0;

    int res = tmNo.compare("3.2");
    if (res == 0) {
        power = -3;
        return power;
    }

    res = tmNo.compare("3.3");
    if (res == 0) {
        power = -6;
        return power;
    }

    std::string mod = bw;
    toupper(mod);
    res = tmNo.compare("1.2");
    if (res == 0) {
        auto it = BandWidth.find(mod);
        if(it == BandWidth.end()) {
            std::cout << "lte:error, The function call resulted in an error : The input parameter BW should be one of{''1.4MHz'', ''3MHz'', ''5MHz'', ''10MHz'', ''15MHz'', ''20MHz''})" << std::endl;
            return power;
        }
        switch(it->second){
            case D1Dot4MHZ:{
                power = -2.990;
                break;
            }
            case D3MHz:{
                power = -4.730;
                break;
            }
            case D5MHz:{
                power = -4.730;
                break;
            }
            case D10MHz:{
                power = -4.730;
                break;
            }
            case D15MHz:{
                power = -4.730;
                break;
            }
            case D20MHz:{
                power = -4.730;
                break;
            }
        }

        return power;
    }
}

//Getting modulation for physical downlink shared channel(PDSCH)
std::string getPDSCHModulation(const std::string tmNo) {
    std::string modulation = "QPSK";
    int res = tmNo.compare("1.1");
    if (res == 0) {
        modulation = "QPSK";
        return modulation;
    }
    res = tmNo.compare("1.2");
    if (res == 0) {
        modulation = { "QPSK","QPSK"};
        return modulation;
    };

    res = tmNo.compare("2");
    if (res == 0) {
        modulation = { "64QAM" };
        return modulation;
    };

    res = tmNo.compare("2a");
    if (res == 0) {
        modulation = { "256QAM" };
        return modulation;
    };

    res = tmNo.compare("2b");
    if (res == 0) {
        modulation = { "1024QAM" };
        return modulation;
    };

    res = tmNo.compare("3.1");
    if (res == 0) {
        modulation = { "64QAM" };
        return modulation;
    };

    res = tmNo.compare("3.1a");
    if (res == 0) {
        modulation = { "256QAM" };
        return modulation;
    };

    res = tmNo.compare("3.1b");
    if (res == 0) {
        modulation = { "1024QAM" };
        return modulation;
    };

    res = tmNo.compare("3.2");
    if (res == 0) {
        modulation = { "16QAM","QPSK"};
        return modulation;
    };

    res = tmNo.compare("3.3");
    if (res == 0) {
        modulation = { "QPSK","16QAM" };
        return modulation;
    };

    return modulation;
}
